/*
 * Copyright (C) 2024 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.android.tools.idea.gradle.catalog

import com.intellij.codeInsight.daemon.impl.HighlightVisitor
import com.intellij.codeInsight.daemon.impl.analysis.HighlightInfoHolder
import com.intellij.codeInsight.daemon.impl.analysis.HighlightingLevelManager
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiFile
import org.jetbrains.kotlin.idea.highlighter.HighlightingFactory
import org.jetbrains.kotlin.idea.highlighter.KotlinHighlightInfoTypeSemanticNames
import org.jetbrains.kotlin.psi.KtDotQualifiedExpression
import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.psi.KtNameReferenceExpression
import org.jetbrains.kotlin.psi.KtSimpleNameExpression
import org.jetbrains.kotlin.psi.KtVisitorVoid

class KtsCatalogHighlighter : HighlightVisitor, KtVisitorVoid() {
  private var myHolder: HighlightInfoHolder? = null
  override fun suitableForFile(file: PsiFile): Boolean =
    file is KtFile && file.virtualFile.name.endsWith("gradle.kts")

  override fun visit(element: PsiElement) = element.accept(this)

  override fun analyze(file: PsiFile, updateWholeFile: Boolean, holder: HighlightInfoHolder, action: Runnable): Boolean {
    val highlightingLevelManager = HighlightingLevelManager.getInstance(file.project)
    if (!highlightingLevelManager.shouldHighlight(file)) return true
    myHolder = holder
    try {
      action.run()
    }
    finally {
      myHolder = null
    }
    return true
  }

  override fun visitDotQualifiedExpression(element: KtDotQualifiedExpression) {
    if (element.isEndOfDotExpression() && hasLiveCatalogReference(element)) element.highlightChildren()
  }

  private fun KtSimpleNameExpression.highlight() {
    assert(myHolder != null)
    val highlightType = KotlinHighlightInfoTypeSemanticNames.EXTENSION_PROPERTY
    myHolder!!.add(HighlightingFactory.highlightName(this, highlightType)?.create())
  }

  private fun KtDotQualifiedExpression.highlightChildren() {
    this.children.forEach {
      when (it) {
        is KtNameReferenceExpression -> it.highlight()
        is KtDotQualifiedExpression -> it.highlightChildren()
        else -> Unit
      }
    }
  }

  override fun clone(): HighlightVisitor = KtsCatalogHighlighter()
}